home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / apps.to.go / DTS.Lib / AEConnect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-04  |  29.4 KB  |  939 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** Program:        DTS.Lib
  5. ** File:        AEConnect.c
  6. ** Written by:  Eric Soldan
  7. **
  8. ** Copyright © 1990-1991 Apple Computer, Inc.
  9. ** All rights reserved.
  10. **
  11. ** This is the custom AppleEvents code used for establishing a connection
  12. ** to another window.  DTS.Lib targets a specific window in an application,
  13. ** not just an application.  It also sends and returns more information
  14. ** about the connection, such as user name, zone, and machine.  This
  15. ** information is two-way, so each user can know who they are connected to.
  16. */
  17.  
  18. /* You may incorporate this sample code into your applications without
  19. ** restriction, though the sample code has been provided "AS IS" and the
  20. ** responsibility for its operation is 100% yours.  However, what you are
  21. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  22. ** after having made changes. If you're going to re-distribute the source,
  23. ** we require that you make it clear in the source that the code was
  24. ** descended from Apple Sample Code, but that you've made changes. */
  25.  
  26.  
  27.  
  28. /*****************************************************************************/
  29.  
  30.  
  31.  
  32. #include "DTS.Lib2.h"
  33. #include "DTS.Lib.protos.h"
  34.  
  35. #ifndef __LOWMEM__
  36. #include <LowMem.h>
  37. #endif
  38.  
  39. #ifndef __RESOURCES__
  40. #include <Resources.h>
  41. #endif
  42.  
  43. #ifndef __TOOLUTILS__
  44. #include <ToolUtils.h>
  45. #endif
  46.  
  47.  
  48.  
  49. /*****************************************************************************/
  50.  
  51.  
  52.  
  53. extern OSType        gDocCreator;
  54. extern short        gMinVersion, gMaxVersion;
  55. extern Boolean        gHasAppleEvents;
  56. extern Cursor        *gCursorPtr;
  57.  
  58. static pascal OSErr        DoAEAnswer(AppleEvent *message, AppleEvent *reply, long refcon);
  59. static pascal OSErr        ReceiveConnect(AppleEvent *message, AppleEvent *reply, long refcon);
  60. static pascal OSErr        ReceiveConnectReply(AppleEvent *message, AppleEvent *reply);
  61.  
  62.  
  63.  
  64. /*****************************************************************************/
  65.  
  66.  
  67.  
  68. static AEHandler keywordsToInstall[] = {
  69.     { kCoreEventClass,        kAEAnswer,            (AEEventHandlerProcPtr)DoAEAnswer,        nil },
  70.     { kCustomEventClass,    keyAppConnect,        (AEEventHandlerProcPtr)ReceiveConnect,    nil },
  71. };        /* These are the custom AppleEvents. */
  72.  
  73. #define kNumKeywords (sizeof(keywordsToInstall) / sizeof(AEHandler))
  74.  
  75.  
  76.  
  77. /*****************************************************************************/
  78. /*****************************************************************************/
  79.  
  80.  
  81.  
  82. /* Install the AppleEvents we use to establish a connection to a specific
  83. ** window.  This is done in addition to installing the required AppleEvents.
  84. ** InitAppleEvents, which installs the required AppleEvents, must be called
  85. ** first, since it sets up some global values. */
  86.  
  87. #pragma segment AppleEvents
  88. void    InitConnectAppleEvents(void)
  89. {
  90.     OSErr    err;
  91.     short    i;
  92.  
  93.     if (gHasAppleEvents) {
  94.         for (i = 0; i < kNumKeywords; ++i) {
  95.  
  96.             if (!keywordsToInstall[i].theUPP)
  97.                 keywordsToInstall[i].theUPP = NewAEEventHandlerProc(keywordsToInstall[i].theHandler);
  98.  
  99.             err = AEInstallEventHandler(
  100.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  101.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  102.                 keywordsToInstall[i].theUPP,        /* The AppleEvent handler. */
  103.                 0L,                                    /* Unused refcon.           */
  104.                 false                                /* Only for our app.       */
  105.             );
  106.  
  107.             if (err) {
  108.                 HCenteredAlert(rErrorAlert, nil, gAlertFilterUPP);
  109.                 return;
  110.             }
  111.         }
  112.     }
  113. }
  114.  
  115.  
  116.  
  117. /*****************************************************************************/
  118.  
  119.  
  120.  
  121. /* This function handles the connect reply.  DTS.framework sends the connect request
  122. ** via kAEQueueReply.  This means that it doesn't necessarily come back immediately.
  123. ** (It actually comes back right away if it is connected to itself.)  The reply
  124. ** normally comes in via a high-level event.  Until this reply comes in, the
  125. ** connection isn't established.  When this reply does come in, the remaining
  126. ** information necessary to establish the connection to a particular window in
  127. ** the target application is recorded. */
  128.  
  129. #pragma segment AppleEvents
  130. static pascal OSErr    DoAEAnswer(AppleEvent *message, AppleEvent *reply, long refcon)
  131. {
  132. #ifndef __MWERKS__
  133. #pragma unused (refcon)
  134. #endif
  135.  
  136.     gCursorPtr = nil;        /* Force re-calc of cursor region and cursor to use. */
  137.     return(ReceiveConnectReply(message, reply));
  138. }
  139.  
  140.  
  141.  
  142. /*****************************************************************************/
  143.  
  144.  
  145.  
  146. /* This is the function that is called to establish a connection to another
  147. ** DTS.framework-based application.  The "other" DTS.framework-based application is probably
  148. ** the same application on another machine.  This code does a bit more than simply connecting
  149. ** to another application.  It targets a specific window within that application.  It doesn't
  150. ** just target zone/machine/application, which is the granularity that AppleEvents gives you.
  151. ** It also passes back and forth some information that is kind of a pain to get, but
  152. ** is nice to have.  One such piece of information is the user name.  This needs to be
  153. ** sent.  It can't be determined from the message from an AppleEvent.  The sender sends
  154. ** the user name, and the receiver returns the remote user name.  The user name is
  155. ** placed in the document record for the window to be used if you wish. */
  156.  
  157. #pragma segment AppleEvents
  158. OSErr    SendConnect(FileRecHndl frHndl, char *theLocNBPType)
  159. {
  160.     AEAddressDesc    remoteLoc;
  161.     OSErr            err;
  162.     long            windTag[2], size;
  163.     char            hstate;
  164.     Ptr                ptr1, ptr2;
  165.     AppleEvent        theAevt, reply;
  166.     Str255            macText, appText;
  167.     Str32            remoteName;
  168.     Handle            remoteNameHndl;
  169.     OSType            sftype;
  170.     FSSpec            myFSS;
  171.     Str255            thisPath;
  172.     Str32            thisApp;
  173.     static PPCFilterUPP    aePortFilterUPP = nil;
  174.  
  175.     err = noErr;
  176.  
  177.     theAevt.dataHandle = reply.dataHandle = nil;
  178.         /* Make sure disposing of the descriptors is okay in all cases.
  179.         ** theAevt and reply aren't necessarily instantiated correctly, so
  180.         ** we need to make sure that the dispose is safe, even if they aren't
  181.         ** valid.  theAevt isn't valid if MakeTarget returns an error.  If
  182.         ** MakeTarget returns an error, then AECreateAppleEvent isn't called
  183.         ** for theAevt.  Similarly, if AESend isn't called, reply isn't valid. */
  184.  
  185.     GetIndString(macText, rPPCText, sTitleText);
  186.     GetIndString(appText, rPPCText, sAppText);
  187.  
  188.     remoteLoc = (*frHndl)->connect.remoteLoc;
  189.     if (!remoteLoc.dataHandle) {
  190.         if (!aePortFilterUPP)
  191.             aePortFilterUPP = NewPPCFilterProc(AEPortFilter);
  192.         err = MakeTarget(&remoteLoc, false, kAEWaitReply, macText, appText,
  193.                         aePortFilterUPP, theLocNBPType);
  194.             /* Generate the target for the remote user. */
  195.     }
  196.  
  197.     (*frHndl)->connect.remoteLoc    = remoteLoc;
  198.     (*frHndl)->connect.windowTag[0] = windTag[0] = (TickCount() & 0xFFFFFFFE);
  199.     (*frHndl)->connect.windowTag[1] = windTag[0];
  200.         /* The windTag fields are used to determine which window is the target
  201.         ** for an incomming AppleEvent.  windTag[0] for the application doing
  202.         ** the connecting will be even, and windTag[1] (the target's ID) will
  203.         ** be odd.  This prevents any accidental occurance where the windTag
  204.         ** fields are the same.  The target application will store these values
  205.         ** reversed.  Any incomming AppleEvent, from either application, will
  206.         ** invert these fields and then scan the window list looking for a window
  207.         ** that has the correct values in these fields.  If there is no such
  208.         ** window, then the window was closed at some point.  Initially, the sender
  209.         ** sets these values to be the same.  Until the sender receives a return
  210.         ** reply for the connect message, the windows aren't officially connected.
  211.         ** When the reply comes in, then the windTag[1] field is set to the reply's
  212.         ** return value. */
  213.  
  214.     if (!err) {        /* Create the AppleEvent... */
  215.         err = AECreateAppleEvent(        /* Create empty AppleEvent.       */
  216.             kCustomEventClass,            /*   Event class.               */
  217.             typeAppConnect,                /*   Event ID.                   */
  218.             &remoteLoc,                    /*   Address of receiving app. */
  219.             kAutoGenerateReturnID,        /*   This value causes the       */
  220.                                         /*   AppleEvent manager to       */
  221.                                         /*   assign a return ID that   */
  222.                                         /*   is unique to the session. */
  223.             kAnyTransactionID,            /*   Ignore transaction ID.       */
  224.             &theAevt                    /*   Location of event.           */
  225.         );
  226.     }
  227.  
  228.     if (!err) {
  229.         sftype = (*frHndl)->fileState.sfType;
  230.         err = AEPutParamPtr(    /* Add document type to AppleEvent. */
  231.             &theAevt,            /*   AppleEvent to add to. */
  232.             keySFType,            /*   AEKeyword.               */
  233.             typeLongInteger,    /*   Actual type.           */
  234.             (Ptr)&sftype,        /*   Pointer to the data.  */
  235.             sizeof(OSType)        /*   Size of the data.       */
  236.         );
  237.     }
  238.  
  239.     if (!err) {
  240.         myFSS = (*frHndl)->fileState.fss;
  241.         err = AEPutParamPtr(    /* Add document name (which is in the FSSpec) to AppleEvent. */
  242.             &theAevt,            /*   AppleEvent to add to. */
  243.             keyFSS,                /*   AEKeyword.               */
  244.             typeFSS,            /*   Desired type.           */
  245.             (Ptr)&myFSS,        /*   Pointer to the data.  */
  246.             sizeof(FSSpec)        /*   Size of the data.       */
  247.         );
  248.     }
  249.  
  250.     if (!err) {
  251.         hstate = HGetState((Handle)frHndl);
  252.         HLock((Handle)frHndl);
  253.         ptr1   = (Ptr)&((*frHndl)->connect);
  254.         ptr2   = (Ptr)&((*frHndl)->connect.endSendInfo);
  255.         size   = (long)ptr2 - (long)ptr1;
  256.         err = AEPutParamPtr(    /* Add file connect info to the AppleEvent. */
  257.             &theAevt,            /*   AppleEvent to add to.             */
  258.             keyAppConnect,        /*   AEKeyword.                         */
  259.             typeAppConnect,        /*   Desired type.                     */
  260.             ptr1,                /*   Pointer to the data to be sent. */
  261.             size                /*   Size of the data to be sent.     */
  262.         );
  263.         HSetState((Handle)frHndl, hstate);
  264.     }
  265.  
  266.     if (!err) {
  267.         remoteName[0] = 0;
  268.         remoteNameHndl = GetAppResource('STR ', -16096, nil);
  269.         if (remoteNameHndl)
  270.             pcpy(remoteName, (StringPtr)(*remoteNameHndl));
  271.         err = AEPutParamPtr(    /* Add user name to AppleEvent. */
  272.             &theAevt,            /*   AppleEvent to add to. */
  273.             keyPascal,            /*   AEKeyword.               */
  274.             typePascal,            /*   Desired type.           */
  275.             (Ptr)remoteName,    /*   Pointer to the data.  */
  276.             remoteName[0] + 1    /*   Size of the data.       */
  277.         );
  278.     }
  279.  
  280.     if (!(*frHndl)->connect.remotePath[0]) (*frHndl)->connect.remoteApp[0]  = 0;
  281.     if (!(*frHndl)->connect.remoteApp[0])  (*frHndl)->connect.remotePath[0] = 0;
  282.  
  283.     if (!err) {
  284.         pcpy(thisPath, (*frHndl)->connect.remotePath);    /* We're the remote to the other guy. */
  285.         err = AEPutParamPtr(        /* Add user name to AppleEvent. */
  286.             &theAevt,                /*   AppleEvent to add to. */
  287.             typePascal2,            /*   AEKeyword.               */
  288.             typePascal2,            /*   Desired type.           */
  289.             (Ptr)thisPath,            /*   Pointer to the data.  */
  290.             thisPath[0] + 1            /*   Size of the data.       */
  291.         );
  292.     }
  293.     (*frHndl)->connect.remotePath[0] = 0;
  294.  
  295.     if (!err) {
  296.         pcpy(thisApp, (*frHndl)->connect.remoteApp);    /* We're the remote to the other guy. */
  297.         err = AEPutParamPtr(    /* Add user name to AppleEvent. */
  298.             &theAevt,            /*   AppleEvent to add to. */
  299.             typePascal3,        /*   AEKeyword.               */
  300.             typePascal3,        /*   Desired type.           */
  301.             (Ptr)thisApp,        /*   Pointer to the data.  */
  302.             thisApp[0] + 1        /*   Size of the data.       */
  303.         );
  304.     }
  305.     (*frHndl)->connect.remoteApp[0] = 0;
  306.  
  307.     if (!err) {        /* If we have an AppleEvent ready to send... */
  308.         err = AESend(            /* Send AppleEvent.              */
  309.             &theAevt,            /*   Our Apple Event to send. */
  310.             &reply,                /*   We may have a reply.      */
  311.             kAEQueueReply,        /*   Type of reply.              */
  312.             kAENormalPriority,    /*   App. send priority.      */
  313.             0,                    /*   We aren't waiting.          */
  314.             nil,                /*   We aren't waiting.          */
  315.             nil                    /*   EventFilterProcPtr.      */
  316.         );
  317.     }
  318.     if (remoteLoc.descriptorType == typeProcessSerialNumber)
  319.         err = ReceiveConnectReply(&reply, &reply);
  320.             /* If we want a queue reply, and if we are sending to ourselves,
  321.             ** then we already have the reply.  Since we are sending to
  322.             ** ourselves, everything happens right away, even for queue reply, so
  323.             ** we must handle the connect reply here.  If we are sending to another
  324.             ** machine, then the reply will come in as a high-level event and we
  325.             ** will process it through the event loop. */
  326.  
  327.     AEDisposeDesc(&theAevt);
  328.     AEDisposeDesc(&reply);
  329.         /* Dispose of the descriptors, created or not.
  330.         ** If not created, no harm done by calling. */
  331.  
  332.     if (err) {
  333.         AEDisposeDesc(&remoteLoc);
  334.         (*frHndl)->connect.remoteLoc.dataHandle = nil;
  335.             /* If we didn't connect, get rid of the target descriptor.  If we
  336.             ** succeeded at connecting, then we keep the descriptor until the
  337.             ** connection is broken by the application. */
  338.  
  339.         (*frHndl)->connect.windowTag[0] = 0;
  340.         (*frHndl)->connect.windowTag[1] = 0;
  341.             /* Mark this window so that it will never be found if we somehow
  342.             ** do get an answer from the receiver, even after failure. */
  343.     }
  344.  
  345.     return(err);
  346. }
  347.  
  348.  
  349.  
  350. /*****************************************************************************/
  351.  
  352.  
  353.  
  354. /* This function receives a connect message from SendConnect.  The connection
  355. ** tasks that the receiver has to do are done here, such as opening a window for
  356. ** this end of the connection, etc.  It also returns whether or not it succeeded,
  357. ** and the user name.  Basically, it establishes the connection, while keeping
  358. ** some data as to whom it is connected to. */
  359.  
  360. #pragma segment AppleEvents
  361. static pascal OSErr    ReceiveConnect(AppleEvent *message, AppleEvent *reply, long refcon)
  362. {
  363. #ifndef __MWERKS__
  364. #pragma unused (refcon)
  365. #endif
  366.  
  367.     OSErr            err;
  368.     FileRecHndl        frHndl;
  369.     char            hstate;
  370.     Ptr                ptr1, ptr2;
  371.     long            size, windTag[2];
  372.     AEAddressDesc    senderTarget;
  373.     DescType        ignoredType;
  374.     Size            ignoredSize;
  375.     OSType            sftype;
  376.     FSSpec            myFSS;
  377.     Str32            remoteZone, remoteMachine, remoteName, remoteApp;
  378.     Str255            theOtherPath, thisPath;
  379.     Str32            theOtherApp,  thisApp;
  380.     Handle            remoteNameHndl;
  381.     short            vers;
  382.  
  383.     err = AEGetParamPtr(    /* Get OSType to determine document type. */
  384.         message,            /*   The AppleEvent.            */
  385.         keySFType,            /*   AEKeyword                   */
  386.         typeLongInteger,    /*   Desired type.               */
  387.         &ignoredType,        /*   Type code.                   */
  388.         (Ptr)&sftype,        /*   Pointer to area for data. */ 
  389.         sizeof(OSType),        /*   Size of the data.           */
  390.         &ignoredSize        /*   Returned size of data.       */
  391.     );
  392.  
  393.     if (!err)
  394.         err = NewDocument(&frHndl, sftype, false);
  395.  
  396.     if (err) return(err);
  397.  
  398.     if (!err) {
  399.         hstate = HGetState((Handle)frHndl);
  400.         HLock((Handle)frHndl);
  401.         ptr1   = (Ptr)&((*frHndl)->connect);
  402.         ptr2   = (Ptr)&((*frHndl)->connect.endSendInfo);
  403.         size   = (long)ptr2 - (long)ptr1;
  404.         err = AEGetParamPtr(    /* Get connect info from the AppleEvent. */
  405.             message,            /*   The AppleEvent.            */
  406.             keyAppConnect,        /*   AEKeyword                   */
  407.             typeAppConnect,        /*   Desired type.               */
  408.             &ignoredType,        /*   Type code.                   */
  409.             ptr1,                /*   Pointer to area for data. */ 
  410.             size,                /*   Size of data area.           */
  411.             &ignoredSize        /*   Returned size of data.       */
  412.         );
  413.         HSetState((Handle)frHndl, hstate);
  414.     }
  415.  
  416.     if (!err) {
  417.         err = AEGetAttributeDesc(    /* Get address of sender.     */
  418.             message,                /*   Get address of sender from message. */
  419.             keyAddressAttr,            /*   We want an address.                 */
  420.             typeWildCard,            /*   We want the address of the sender.     */
  421.             &senderTarget            /*   Address of sender.                     */
  422.         );
  423.         if (!err) {
  424.             (*frHndl)->connect.remoteLoc = senderTarget;
  425.             err = AEGetParamPtr(    /* Get FSSpec (for document name) from AppleEvent. */
  426.                 message,            /*   The AppleEvent.            */
  427.                 keyFSS,                /*   AEKeyword                   */
  428.                 typeFSS,            /*   Desired type.               */
  429.                 &ignoredType,        /*   Type code.                   */
  430.                 (Ptr)&myFSS,        /*   Pointer to area for data. */ 
  431.                 sizeof(FSSpec),        /*   Size of the data.           */
  432.                 &ignoredSize        /*   Returned size of data.       */
  433.             );
  434.             if (!err)
  435.                 pcpy((*frHndl)->fileState.fss.name, (StringPtr)myFSS.name);
  436.         }
  437.         if (!err) {
  438.             err = AEGetParamPtr(    /* Get user name from AppleEvent. */
  439.                 message,            /*   The AppleEvent.            */
  440.                 keyPascal,            /*   AEKeyword                   */
  441.                 typePascal,            /*   Desired type.               */
  442.                 &ignoredType,        /*   Type code.                   */
  443.                 (Ptr)remoteName,    /*   Pointer to area for data. */ 
  444.                 sizeof(Str255),        /*   Size of the data.           */
  445.                 &ignoredSize        /*   Returned size of data.       */
  446.             );
  447.             (*frHndl)->connect.remoteName[0] = 0;
  448.             if (!err) {
  449.                 pcpy((*frHndl)->connect.remoteName, remoteName);
  450.                 remoteZone[0] = remoteMachine[0] = 0;
  451.                 GetTargetInfo(senderTarget, remoteZone, remoteMachine, remoteApp);
  452.                 pcpy((*frHndl)->connect.remoteZone, remoteZone);
  453.                 pcpy((*frHndl)->connect.remoteMachine, remoteMachine);
  454.             }
  455.         }
  456.  
  457.         theOtherPath[0] = theOtherApp[0] = 0;
  458.         if (!err) {
  459.             err = AEGetParamPtr(    /* Get user name from AppleEvent. */
  460.                 message,            /*   The AppleEvent.            */
  461.                 typePascal2,        /*   AEKeyword                   */
  462.                 typePascal2,        /*   Desired type.               */
  463.                 &ignoredType,        /*   Type code.                   */
  464.                 (Ptr)theOtherPath,    /*   Pointer to area for data. */ 
  465.                 sizeof(Str255),        /*   Size of the data.           */
  466.                 &ignoredSize        /*   Returned size of data.       */
  467.             );
  468.         }
  469.         if (!err) {
  470.             err = AEGetParamPtr(    /* Get user name from AppleEvent. */
  471.                 message,            /*   The AppleEvent.            */
  472.                 typePascal3,        /*   AEKeyword                   */
  473.                 typePascal3,        /*   Desired type.               */
  474.                 &ignoredType,        /*   Type code.                   */
  475.                 (Ptr)theOtherApp,    /*   Pointer to area for data. */ 
  476.                 sizeof(Str255),        /*   Size of the data.           */
  477.                 &ignoredSize        /*   Returned size of data.       */
  478.             );
  479.         }
  480.     }
  481.  
  482.     if (!err) {        /* If we got the remote user address... */
  483.  
  484.         (*frHndl)->connect.windowTag[0] = windTag[0] = (TickCount() | 0x01);
  485.         (*frHndl)->connect.connected = true;
  486.  
  487.         vers = (*frHndl)->d.doc.fhInfo.version;
  488.         if ((vers < gMinVersion) || (vers > gMaxVersion))
  489.             err = errAEWrongDataType;
  490.                 /* Incompatible file format. */
  491.  
  492.         if (!err) {
  493.             windTag[1] = (*frHndl)->connect.windowTag[1];
  494.             err = AEPutParamPtr(    /* Return receiver window ID. */
  495.                 reply,                /*   The AppleEvent.            */
  496.                 keyWindowTag,        /*   AEKeyword                   */
  497.                 typeDoubleLong,        /*   Type code.                   */
  498.                 (Ptr)&windTag[0],    /*   Pointer to area for data. */ 
  499.                 2 * sizeof(long)    /*   Size of data area.           */
  500.             );
  501.         }
  502.  
  503.         if (!err) {
  504.             remoteName[0] = 0;
  505.             remoteNameHndl = GetAppResource('STR ', -16096, nil);
  506.             if (remoteNameHndl)
  507.                 pcpy(remoteName, (StringPtr)(*remoteNameHndl));
  508.             err = AEPutParamPtr(    /* Return receiver user name. */
  509.                 reply,                /*   The AppleEvent.            */
  510.                 keyPascal,            /*   AEKeyword                   */
  511.                 typePascal,            /*   Type code.                   */
  512.                 (Ptr)remoteName,    /*   Pointer to area for data. */ 
  513.                 remoteName[0] + 1    /*   Size of data area.           */
  514.             );
  515.         }
  516.  
  517.         if (!err) {
  518.             if (theOtherPath[0]) {
  519.                 pcpy((*frHndl)->connect.remotePath, theOtherPath);
  520.                 pcpy((*frHndl)->connect.remoteApp,  theOtherApp);
  521.                 GetFullPathAndAppName(thisPath, thisApp);
  522.                 err = AEPutParamPtr(    /* Return receiver user name. */
  523.                     reply,                /*   The AppleEvent.            */
  524.                     typePascal2,        /*   AEKeyword                   */
  525.                     typePascal2,        /*   Type code.                   */
  526.                     (Ptr)thisPath,        /*   Pointer to area for data. */ 
  527.                     thisPath[0] + 1        /*   Size of data area.           */
  528.                 );
  529.                 if (!err) {
  530.                     err = AEPutParamPtr(    /* Return receiver user name. */
  531.                         reply,                /*   The AppleEvent.            */
  532.                         typePascal3,        /*   AEKeyword                   */
  533.                         typePascal3,        /*   Type code.                   */
  534.                         (Ptr)thisApp,        /*   Pointer to area for data. */ 
  535.                         thisApp[0] + 1        /*   Size of data area.           */
  536.                     );
  537.                 }
  538.             }
  539.         }
  540.  
  541.         if (!err)
  542.             err = DoNewWindow(frHndl, nil, GetNextWindow(nil, 0), (WindowPtr)-1);
  543.                 /* If connecting worked, create a window for the document. */
  544.     }
  545.  
  546.     if (err)
  547.         DisposeDocument(frHndl);
  548.  
  549.     if (!err)
  550.         NotifyUser();
  551.  
  552.     return(err);
  553. }
  554.  
  555.  
  556.  
  557. /*****************************************************************************/
  558.  
  559.  
  560.  
  561. /* This function is called when you want to determine which window an AppleEvent
  562. ** is targeted for.  DTS.framework AppleEvents send two long values along with the AppleEvent
  563. ** to determine which window is the target window.  One of the longs is an ID for the
  564. ** sender, and the other is an ID for the receiver.  When a connection is established,
  565. ** these values are saved for both the sender and the receiver.  This allows the
  566. ** AppleEvent to be sent in either direction and still be targeted to the correct window.
  567. ** To find which window is the target, get these two longs out of the AppleEvent and then
  568. ** call GetAEWindow.  The first value is always the ID of the machine itself, and the
  569. ** second value is always the ID of the remote machine.  Due to this, you will need to
  570. ** reverse the order of these ID's for incomming DTS.framework AppleEvents. */
  571.  
  572. #pragma segment AppleEvents
  573. static pascal OSErr    ReceiveConnectReply(AppleEvent *message, AppleEvent *reply)
  574. {
  575. #ifndef __MWERKS__
  576. #pragma unused (reply)
  577. #endif
  578.  
  579.     OSErr            err, replyErr;
  580.     DescType        actualType;
  581.     long            windTag[2], actualSize;
  582.     WindowPtr        window;
  583.     FileRecHndl        frHndl;
  584.     Str32            remoteZone, remoteMachine, remoteApp, remoteName;
  585.     Str255            theOtherPath;
  586.     Str32            theOtherApp;
  587.  
  588.     err = AEGetParamPtr(        /* Check for a receiver error... */
  589.         message,                /*   The AppleEvent.            */
  590.         keyReplyErr,            /*   AEKeyword                   */
  591.         typeShortInteger,        /*   Desired type.               */
  592.         &actualType,            /*   Type code.                   */
  593.         (Ptr)&replyErr,            /*   Pointer to area for data. */ 
  594.         sizeof(short),            /*   Size of data area.           */
  595.         &actualSize                /*   Returned size of data.       */
  596.     );
  597.     if (err == errAEDescNotFound)
  598.         err = noErr;
  599.     else
  600.         if (!err)
  601.             err = replyErr;
  602.  
  603.     if (!err) {
  604.         err = AEGetParamPtr(    /* Get receiver window ID. */
  605.             message,            /*   The AppleEvent.            */
  606.             keyWindowTag,        /*   AEKeyword                   */
  607.             typeDoubleLong,        /*   Desired type.               */
  608.             &actualType,        /*   Type code.                   */
  609.             (Ptr)&windTag[0],    /*   Pointer to area for data. */ 
  610.             2 * sizeof(long),    /*   Size of data area.           */
  611.             &actualSize            /*   Returned size of data.       */
  612.         );
  613.     }
  614.  
  615.     if (!err) {        /* If we got the receiver window ID... */
  616.  
  617.         window = GetAEWindow(windTag[1], windTag[1]);
  618.             /* The ID's are still both ours, since this is where we
  619.             ** get the receiver's ID returned.  windTag[0] holds the
  620.             ** receiver's ID, and windTag[1] holds ours. */
  621.  
  622.         if (window) {
  623.             frHndl = (FileRecHndl)GetWRefCon(window);
  624.             if (!(*frHndl)->connect.connected) {
  625.                 err = AEGetParamPtr(
  626.                     message,            /* The AppleEvent.              */
  627.                     keyPascal,            /* AEKeyword                 */
  628.                     typePascal,            /* Desired type.             */
  629.                     &actualType,        /* Type code.                 */
  630.                     (Ptr)remoteName,    /* Pointer to area for data. */ 
  631.                     sizeof(Str255),        /* Size of data area.         */
  632.                     &actualSize            /* Returned size of data.     */
  633.                 );
  634.  
  635.                 if (!err) {
  636.                     err = AEGetParamPtr(
  637.                         message,            /* The AppleEvent.              */
  638.                         typePascal2,        /* AEKeyword                 */
  639.                         typePascal2,        /* Desired type.             */
  640.                         &actualType,        /* Type code.                 */
  641.                         (Ptr)theOtherPath,    /* Pointer to area for data. */ 
  642.                         sizeof(Str255),        /* Size of data area.         */
  643.                         &actualSize            /* Returned size of data.     */
  644.                     );
  645.                 }
  646.                 if (err == errAEDescNotFound) {
  647.                     theOtherPath[0] = 0;
  648.                     err = noErr;
  649.                 }
  650.                 if (!err) {
  651.                     err = AEGetParamPtr(
  652.                         message,            /* The AppleEvent.              */
  653.                         typePascal3,        /* AEKeyword                 */
  654.                         typePascal3,        /* Desired type.             */
  655.                         &actualType,        /* Type code.                 */
  656.                         (Ptr)theOtherApp,    /* Pointer to area for data. */ 
  657.                         sizeof(Str255),        /* Size of data area.         */
  658.                         &actualSize            /* Returned size of data.     */
  659.                     );
  660.                 }
  661.                 if (err == errAEDescNotFound) {
  662.                     theOtherApp[0] = 0;
  663.                     err = noErr;
  664.                 }
  665.  
  666.                 (*frHndl)->connect.remoteName[0] = 0;
  667.                 if (!err) {        /* Connection is for sure, so remember what we need. */
  668.                     (*frHndl)->connect.windowTag[1] = windTag[0];
  669.                     pcpy((*frHndl)->connect.remoteName, remoteName);
  670.                     GetTargetInfo((*frHndl)->connect.remoteLoc,
  671.                                   remoteZone, remoteMachine, remoteApp);
  672.                     pcpy((*frHndl)->connect.remoteZone,    remoteZone);
  673.                     pcpy((*frHndl)->connect.remoteMachine, remoteMachine);
  674.                     pcpy((*frHndl)->connect.remotePath,    theOtherPath);
  675.                     pcpy((*frHndl)->connect.remoteApp,     theOtherApp);
  676.                     (*frHndl)->connect.connected = true;
  677.                 }
  678.                 else
  679.                     (*frHndl)->connect.windowTag[0] = (*frHndl)->connect.windowTag[1] = 0;
  680.             }
  681.         }
  682.     }
  683.  
  684.     return(err);
  685. }
  686.  
  687.  
  688.  
  689. /*****************************************************************************/
  690.  
  691.  
  692.  
  693. /* Find the window with the specified window ID's. */
  694.  
  695. #pragma segment AppleEvents
  696. WindowPtr    GetAEWindow(long windTag_0, long windTag_1)
  697. {
  698.     WindowPeek    window;
  699.     FileRecHndl    frHndl;
  700.  
  701.     for (window = LMGetWindowList(); window; window = window->nextWindow) {
  702.         if (IsAppWindow((WindowPtr)window)) {
  703.             frHndl = (FileRecHndl)GetWRefCon((WindowPtr)window);
  704.             if (
  705.                 ((*frHndl)->connect.windowTag[0] == windTag_0) &&
  706.                 ((*frHndl)->connect.windowTag[1] == windTag_1)
  707.             ) return((WindowPtr)window);
  708.         }
  709.     }
  710.  
  711.     return(nil);
  712. }
  713.  
  714.  
  715.  
  716. /*****************************************************************************/
  717.  
  718.  
  719.  
  720. #pragma segment AppleEvents
  721. void    GetFullPathAndAppName(StringPtr path, StringPtr app)
  722. {
  723.     ProcessSerialNumber    psn;
  724.     ProcessInfoRec        pinfo;
  725.     FSSpec                fss;
  726.  
  727.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  728.     pinfo.processName       = app;
  729.     pinfo.processAppSpec    = &fss;
  730.  
  731.     psn.lowLongOfPSN  = kCurrentProcess;
  732.     psn.highLongOfPSN = kNoProcess;
  733.     GetProcessInformation(&psn, &pinfo);
  734.  
  735.     PathNameFromDirID(pinfo.processAppSpec->parID, pinfo.processAppSpec->vRefNum, path);
  736. }
  737.  
  738.  
  739.  
  740. /*****************************************************************************/
  741.  
  742.  
  743.  
  744. #pragma segment AppleEvents
  745. void    AllowAutoReconnect(FileRecHndl frHndl)
  746. {
  747.     Str255    path;
  748.     Str32    app;
  749.  
  750.     GetFullPathAndAppName(path, app);
  751.     pcpy((*frHndl)->connect.remotePath, path);
  752.     pcpy((*frHndl)->connect.remoteApp,  app);
  753. }
  754.  
  755.  
  756.  
  757. /*****************************************************************************/
  758.  
  759.  
  760.  
  761. /* This function doesn't allow the PPCBrowser to display any applications other
  762. ** than the designated application(s). */
  763.  
  764. #pragma segment AppleEvents
  765. pascal Boolean    AEPortFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  766. {
  767. #ifndef __MWERKS__
  768. #pragma unused (locationName)
  769. #endif
  770.  
  771.     OSType    type;
  772.  
  773.     if (thePortInfo->name.portKindSelector == ppcByString) {
  774.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  775.             /* The BlockMove is so that we don't get an address error
  776.             ** on a 68000-based machine due to referencing a long at
  777.             ** an odd-address. */
  778.         if (type == gDocCreator) return(true);
  779.     }
  780.  
  781.     return(false);
  782. }
  783.  
  784.  
  785.  
  786. /*****************************************************************************/
  787.  
  788.  
  789.  
  790. #pragma segment AppleEvents
  791. OSErr    GetRemoteProcessTarget(FileRecHndl frHndl, AEDesc *retDesc, GRPTProcPtr proc)
  792. {
  793.     OSErr            err;
  794.     char            hstate;
  795.     PortInfoRec        info;        /* Just one, please. */
  796.     LocationNameRec    loc;
  797.     short            indx, reqCount, actCount;
  798.     TargetID        theID;
  799.  
  800.     retDesc->dataHandle = nil;        /* So caller can dispose always. */
  801.  
  802.     hstate = LockHandleHigh((Handle)frHndl);
  803.     loc.locationKindSelector = ppcNBPLocation;        /* Using an NBP construct. */
  804.     pcpy(loc.u.nbpEntity.objStr,  (*frHndl)->connect.remoteMachine);
  805.     pcpy(loc.u.nbpEntity.zoneStr, (*frHndl)->connect.remoteZone);
  806.     pcpy(loc.u.nbpEntity.typeStr, "\pPPCToolBox");
  807.     HSetState((Handle)frHndl, hstate);
  808.  
  809.     indx     = 0;
  810.     reqCount = 1;
  811.     actCount = 0;
  812.     err = DoIPCListPorts(&indx, &reqCount, &actCount, &loc, &info, proc);
  813.     if (err) return(err);
  814.  
  815.     if (actCount) {
  816.         theID.name = info.name;
  817.         theID.location = loc;
  818.         err = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), retDesc);
  819.     }
  820.  
  821.     return(err);
  822. }
  823.  
  824.  
  825.  
  826. /*****************************************************************************/
  827.  
  828.  
  829.  
  830. /* Don't allow DoIPCListPorts to find anything but the finder. */
  831.  
  832. #pragma segment AppleEvents
  833. static pascal Boolean    FinderFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo);
  834. static pascal Boolean    FinderFilter(LocationNamePtr locationName, PortInfoPtr thePortInfo)
  835. {
  836. #ifndef __MWERKS__
  837. #pragma unused (locationName)
  838. #endif
  839.  
  840.     OSType    type;
  841.  
  842.     if (thePortInfo->name.portKindSelector == ppcByString) {
  843.         BlockMove(thePortInfo->name.u.portTypeStr + 1, (Ptr)&type, 4);
  844.             /* The BlockMove is so that we don't get an address error
  845.             ** on a 68000-based machine due to referencing a long at
  846.             ** an odd-address. */
  847.         if (type == 'MACS') return(true);
  848.     }
  849.  
  850.     return(false);
  851. }
  852.  
  853. /***/
  854.  
  855. OSErr    LaunchRemoteApp(FileRecHndl frHndl)
  856. {
  857.     OSErr            err;
  858.     AEDesc            remoteDesc, aeDirDesc, listElem, fileList;
  859.     AppleEvent        aevt, aeReply;
  860.     char            hstate;
  861.     Str255            path;
  862.     Str255            app;
  863.     AliasHandle        dirAlias, fileAlias;
  864.     ConnectRec        ac;
  865.  
  866.     err = noErr;
  867.     ac  = (*frHndl)->connect;
  868.  
  869.     if (ac.remotePath[0]) {
  870.  
  871.         DoSetCursor(*GetCursor(watchCursor));
  872.  
  873.         if (!GetRemoteProcessTarget(frHndl, &remoteDesc, FinderFilter)) {
  874.  
  875.             err = AECreateAppleEvent('FNDR', 'sope', &remoteDesc,
  876.                                       kAutoGenerateReturnID, kAnyTransactionID, &aevt);
  877.             AEDisposeDesc(&remoteDesc);
  878.  
  879.             if (!err) {
  880.  
  881.                 hstate = LockHandleHigh((Handle)frHndl);
  882.                 pcpy(path, (*frHndl)->connect.remotePath);
  883.                 pcpy(app, path);
  884.                 pcat(app,  (*frHndl)->connect.remoteApp);
  885.                 HSetState((Handle)frHndl, hstate);
  886.                 NewAliasMinimalFromFullPath(path[0], (path + 1), "\p", "\p", &dirAlias);
  887.                 NewAliasMinimalFromFullPath(app[0],  (app + 1),  "\p", "\p", &fileAlias);
  888.  
  889.                 err = AECreateList(nil, 0, false, &fileList);
  890.  
  891.                 if (!err) {
  892.                     hstate = LockHandleHigh((Handle)dirAlias);
  893.                     err = AECreateDesc(typeAlias, (Ptr)*dirAlias,
  894.                                        GetHandleSize((Handle)dirAlias), &aeDirDesc);
  895.                     HSetState((Handle)dirAlias, hstate);
  896.                 }
  897.                 DisposeHandle((Handle)dirAlias);
  898.  
  899.                 if (!err) {
  900.                     err = AEPutParamDesc(&aevt, keyDirectObject, &aeDirDesc);
  901.                     AEDisposeDesc(&aeDirDesc);
  902.                 }
  903.  
  904.                 if (!err) {
  905.                     hstate = LockHandleHigh((Handle)fileAlias);
  906.                     err = AECreateDesc(typeAlias, (Ptr)*fileAlias,
  907.                                        GetHandleSize((Handle)fileAlias), &listElem);
  908.                     HSetState((Handle)dirAlias, hstate);
  909.                 }
  910.                 DisposeHandle((Handle)fileAlias);
  911.  
  912.                 if (!err) {
  913.                     err = AEPutDesc(&fileList, 0, &listElem);
  914.                     AEDisposeDesc(&listElem);
  915.                 }
  916.  
  917.                 if (!err) {
  918.                     err = AEPutParamDesc(&aevt, 'fsel', &fileList);
  919.                     AEDisposeDesc(&fileList);
  920.                 }
  921.  
  922.                 if (!err) {
  923.                     err = AESend(&aevt, &aeReply,
  924.                                 (kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer),
  925.                                 kAENormalPriority, kAEDefaultTimeout, nil, nil);
  926.                     AEDisposeDesc(&aeReply);
  927.                 }
  928.  
  929.                 AEDisposeDesc(&aevt);
  930.             }
  931.         }
  932.     }
  933.  
  934.     return(err);
  935. }
  936.  
  937.  
  938.  
  939.